/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import { ArkAssignStmt, ArkField, ArkIfStmt, ArkInvokeStmt, ArkMethod, ArkReturnStmt, ArkReturnVoidStmt, ArkThrowStmt, Decorator, Stmt } from "../../ArkAnalyzer/src";
import { ArkFieldDefStmt, ArkMethodDefStmt } from "../Nodes";
import { JsonValue } from "./jsonValue";
import { parseArkValue } from "./values";

class BasicStmt {
    protected json: JsonValue = new JsonValue();

    constructor(arkStmt: Stmt){
        this.json.setIdentifier(arkStmt.constructor.name);
    }

    public getJson(){
        return this.json.getJson();
    }
}

export function parseArkStmt(arkStmt: Stmt): Record<string, any> {
    let stmt: BasicStmt;

    if (arkStmt instanceof ArkAssignStmt) {
        stmt = new AssignStmt(arkStmt);
    }
    else if(arkStmt instanceof ArkInvokeStmt) {
        stmt = new InvokeStmt(arkStmt);
    }
    else if(arkStmt instanceof ArkIfStmt) {
        stmt = new IfStmt(arkStmt);
    }
    else if(arkStmt instanceof ArkReturnVoidStmt) {
        stmt = new ReturnVoidStmt(arkStmt);
    }
    else if(arkStmt instanceof ArkReturnStmt) {
        stmt = new ReturnStmt(arkStmt);
    }
    else if(arkStmt instanceof ArkThrowStmt) {
        stmt = new ThrowStmt(arkStmt);
    }
    else if (arkStmt instanceof ArkMethodDefStmt) {
        stmt = new MethodDefStmt(arkStmt);
    }
    else if (arkStmt instanceof ArkFieldDefStmt) {
        stmt = new FieldDefStmt(arkStmt);
    }
    else {
        stmt = new BasicStmt(arkStmt);
    }
    
    return stmt.getJson();
}

class FieldDefStmt extends BasicStmt {
    constructor (arkFieldDefStmt: ArkFieldDefStmt) {
        super(arkFieldDefStmt);
        this.parse(arkFieldDefStmt);
    }

    private parse(arkFieldDefStmt: ArkFieldDefStmt) {
        let arkField: ArkField = arkFieldDefStmt.getArkField();
        let decorators: string[] = [];
        for (const decorator of arkField.getDecorators()) {
            // decorators.push({
            //     kind: decorator.kind,
            //     content: decorator.content,
            //     param: decorator.param
            // })
            decorators.push(decorator.toString());
        }
        this.json.setDecorators(decorators);
    }
}

class MethodDefStmt extends BasicStmt {
    constructor(arkMethodDefStmt: ArkMethodDefStmt){
        super(arkMethodDefStmt);
        this.parse(arkMethodDefStmt);
    }

    private parse(arkMethodDefStmt: ArkMethodDefStmt) {
        let args: any[] = [];
        for (const parameter of  arkMethodDefStmt.getParameters()) {
            args.push(parseArkValue(parameter));
        }
        this.json.setArgs(args);

        let method: ArkMethod = arkMethodDefStmt.getMethod();
        let decorators: any[] = [];
        for (const decorator of method.getDecorators()) {
            decorators.push(decorator.toString());
        }
        this.json.setDecorators(decorators);
    }
}

class AssignStmt extends BasicStmt {
    constructor(arkAssignStmt: ArkAssignStmt){
        super(arkAssignStmt);
        this.parse(arkAssignStmt);
    }

    private parse(arkAssignStmt: ArkAssignStmt) {
        this.json.setLeftOp(parseArkValue(arkAssignStmt.getLeftOp()));
        this.json.setRightOp(parseArkValue(arkAssignStmt.getRightOp()));
    }
}

class InvokeStmt extends BasicStmt {
    constructor(arkInvokeStmt: ArkInvokeStmt){
        super(arkInvokeStmt);
        this.parse(arkInvokeStmt);
    }

    private parse(arkInvokeStmt: ArkInvokeStmt) {
        this.json.setInvokeExpr(parseArkValue(arkInvokeStmt.getInvokeExpr()));
    }
}

class IfStmt extends BasicStmt {
    constructor(arkIfStmt: ArkIfStmt){
        super(arkIfStmt);
        this.parse(arkIfStmt);
    }

    private parse(arkIfStmt: ArkIfStmt) {
        this.json.setConditionExpr(parseArkValue(arkIfStmt.getConditionExpr()));
    }
}

class ReturnVoidStmt extends BasicStmt {
    constructor(arkReturnVoidStmt: ArkReturnVoidStmt){
        super(arkReturnVoidStmt);
    }
}

class ReturnStmt extends BasicStmt {
    constructor(arkReturnStmt: ArkReturnStmt){
        super(arkReturnStmt);
        this.parse(arkReturnStmt);
    }

    private parse(arkReturnStmt: ArkReturnStmt) {
        this.json.setOp(parseArkValue(arkReturnStmt.getOp()));
    }
}

class ThrowStmt extends BasicStmt {
    constructor(arkThrowStmt: ArkThrowStmt){
        super(arkThrowStmt);
        this.parse(arkThrowStmt);
    }

    private parse(arkThrowStmt: ArkThrowStmt) {
        this.json.setOp(parseArkValue(arkThrowStmt.getOp()));
    }
}
